package de.hwrberlin.remo.export.textexport;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;

import de.hwrberlin.remo.export.ModelExporter;
import de.hwrberlin.remo.model.AndRule;
import de.hwrberlin.remo.model.Fact;
import de.hwrberlin.remo.model.KnowledgeBase;
import de.hwrberlin.remo.model.KnowledgeBaseElement;
import de.hwrberlin.remo.model.LinksFromRules;
import de.hwrberlin.remo.model.OrRule;
import de.hwrberlin.remo.model.Rule;

public class SimpleTextExport implements ModelExporter {

	private final String LINE_BREAK   = "\n";
	private final String COMMENT_SIGN = "#";
	
	@Override
	public void exportKnowledgeBase(String modelFilePath, KnowledgeBase base) {
		if(base == null) {
			return;
		}
		
		Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
		
		FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
		String selectedFilePath = fileDialog.open();
		
		if(selectedFilePath != null) {
			File outputFile = new File(selectedFilePath);
			
			if(outputFile != null) {
				try {
					BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile));
				
					writeHead(writer, base);
					writeFacts(writer, base);
					writeRules(writer, base);
					
					writer.flush();
					writer.close();
					
				} catch (FileNotFoundException e) {
					e.printStackTrace();

				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	private void writeHead(BufferedWriter writer, KnowledgeBase base) throws IOException {
		
		// Write knowledge base name
		writer.write(COMMENT_SIGN + " Knowledge Base: ");
		String name = base.getName();
		if(name != null) {
			writer.write(name);
		}
		
		writer.write(LINE_BREAK);
		
		// Write knowledge base description
		writer.write(COMMENT_SIGN + " Description: ");
		String description = base.getDescription();
		if(description != null) {
			writer.write(description);
		}
		
		writeEmptyLine(writer);
	}
	
	
	private void writeFacts(BufferedWriter writer, KnowledgeBase base) throws IOException {
		writer.write("Facts:");
		
		for(Fact fact : base.getFacts()) {
			writer.write(LINE_BREAK);
			
			// Write fact description
			String description = fact.getDescription();
			if(description != null && description.length() > 0) {
				writer.write(COMMENT_SIGN + description);
				writer.write(LINE_BREAK);
			}

			// Write fact name
			String name = fact.getName();
			if(name != null && name.length() > 0) {
				writer.write(name);
			} else {
				writer.write(fact.toString());
			}
			
			writer.write(LINE_BREAK);
		}
		
		writeEmptyLine(writer);
	}
	
	private void writeRules(BufferedWriter writer, KnowledgeBase base) throws IOException {
		// Write rules
		writer.write("Rules: ");
		for(Rule rule : base.getRules()) {
			String ruleSign = getRuleSign(rule);
			writer.write(LINE_BREAK);
			
			// Write rule description
			String description = rule.getDescription();
			if(description != null && description.length() > 0) {
				writer.write(COMMENT_SIGN + description);
				writer.write(LINE_BREAK);
			}

			// Collect premises names
			List<String> premiseNames = new ArrayList<String>();
			for(LinksFromRules premise : rule.getRelatedlinkedrules()) {
				KnowledgeBaseElement element = premise.getElement();
				String elementName = element.getName();

				if(elementName != null && elementName.length() > 0) {
					premiseNames.add(elementName);
				} else {
					premiseNames.add(element.toString());
				}
			}
			
			// Concat premises (if existent)
			if(!premiseNames.isEmpty()) {
				writer.write("IF " + premiseNames.get(0));
				
				for(int i = 1; i < premiseNames.size(); i++) {
					writer.write(" " + ruleSign + " " + premiseNames.get(i));
				}
				
				writer.write(" THEN ");
			}
			
			// Add rule name
			String name = rule.getName();
			if(name != null && name.length() > 0) {
				writer.write(name);
			} else {
				writer.write(rule.toString());
			}
			
			writer.write(LINE_BREAK);
		}
		
		writeEmptyLine(writer);
	}
	
	private void writeEmptyLine(BufferedWriter writer) throws IOException {
		writer.write(LINE_BREAK);
		writer.write(LINE_BREAK);
	}
	
	private String getRuleSign(Rule rule) {
		if(rule instanceof AndRule) {
			return "AND";
		
		} else if(rule instanceof OrRule) {
			return "OR";
		}
		
		return "";
	}
}